  //
  //  UserController.swift
  //  hello
  //
  //  Created by 赵康 on 2024/11/11.
  //

import Vapor
import Fluent
@preconcurrency import Redis

struct UserController: RouteCollection {
    // 登录凭证过期时间 (7天)
  private let sessionExpiration: TimeAmount = .hours(7 * 24)
  
  func boot(routes: any RoutesBuilder) throws {
    let users = routes.grouped("\(RouteEnum.users.rawValue)") // /users
    
      // 注册相关路由
    users.post("\(RouteEnum.register.rawValue)", use: register) // 新的邮箱+密码注册路由
    users.get("\(RouteEnum.getTermsInfo.rawValue)", use: getTermsInfo) // 获取用户协议信息
    users.post("\(RouteEnum.updateTermsAgreement.rawValue)", use: updateTermsAgreement) // 更新用户协议同意
      // 登录相关路由
    users.post("\(RouteEnum.login.rawValue)", use: login) // /users/login
    users.post("\(RouteEnum.loginWithEmailCode.rawValue)", use: loginWithEmailCode)
    users.post("\(RouteEnum.loginWithPhoneCode.rawValue)", use: loginWithPhoneCode)
    
    // Apple登录路由
    users.post("\(RouteEnum.appleSignIn.rawValue)", use: appleSignIn)
    
    // 密码重置相关路由
    users.post("\(RouteEnum.forgetPassword.rawValue)", use: forgetPassword)
    users.post("\(RouteEnum.resetPassword.rawValue)", use: resetPassword)
    
      // 验证码相关路由
    users
      .post(
        "\(RouteEnum.sendEmailVerificationCode.rawValue)",
        use: sendEmailVerificationCode
      ) // /users/ver
    users
      .post(
        "\(RouteEnum.sendSMSVerificationCode.rawValue)",
        use: sendSMSVerificationCode
      )
    
      // 需要身份验证的路由
    let protected = users.grouped(AuthMiddleware()) // /users
    protected.post("\(RouteEnum.logout.rawValue)", use: logout) // /users/logout
    protected.get("\(RouteEnum.me.rawValue)", use: fetchMe) // /users/me
    protected.post("\(RouteEnum.update.rawValue)", use: updateMe) // /users/update
    
      // 邮箱手机绑定/修改路由
    protected
      .post("\(RouteEnum.bindPhone.rawValue)", use: bindPhone)
    protected
      .post("\(RouteEnum.bindEmail.rawValue)", use: bindEmail)
    
    // 头像上传相关路由
    let avatarController = AvatarUploadController()
    protected
      .post("\(RouteEnum.getAvatarUploadURL.rawValue)", use: avatarController.getUploadURL)
    protected
      .post("\(RouteEnum.confirmAvatarUpload.rawValue)", use: avatarController.confirmUpload)
    protected
      .post("\(RouteEnum.cropAvatar.rawValue)", use: avatarController.cropAvatar)
    protected
      .post("\(RouteEnum.rotateAvatar.rawValue)", use: avatarController.rotateAvatar)
  }
  
  // MARK: - 注册方法
  
  // 使用邮箱+密码注册（不需要验证码）
  @Sendable
  func register(req: Request) async throws -> BasicResponse {
    let registerData: User.EmailPasswordRegister = try req.content.decode(User.EmailPasswordRegister.self)
    
    // 检查用户协议是否同意
    if !registerData.agreedToTerms {
      throw Abort(.badRequest, reason: "请先同意用户协议")
    }
    
    // 检查邮箱是否已被注册
    if try await User.query(on: req.db)
      .filter(\.$email == registerData.email)
      .first() != nil {
      throw Abort(.conflict, reason: "该邮箱已被注册，请直接登录")
    }
    
    // 生成随机中文用户名：[积极的形容词]的[动物名词]
    let randomName: String = generateChineseRandomName()
    
    // 检查用户名是否已被使用
    if try await User.query(on: req.db)
      .filter(\.$name == randomName)
      .first() != nil {
      // 如果已存在，重新生成一个
      let newRandomName: String = generateChineseRandomName()
      
      // 再次检查，几乎不可能重复，但为安全起见
      if try await User.query(on: req.db)
        .filter(\.$name == newRandomName)
        .first() != nil {
        throw Abort(.conflict, reason: "用户名生成失败，请稍后重试")
      }
    }
    
    // 创建用户
    let user: User = User(
      name: randomName,
      email: registerData.email,
      password: try Bcrypt.hash(registerData.password),
      phone: "", // 空手机号，后续可以绑定
      isDeleted: false,
      isEmailVerified: true, // 设为true，因为我们不需要验证
      isPhoneVerified: false,
      isSubscribed: false,
      currentStreak: 0,
      dailyGoal: 600, // 确保设置默认学习目标为10分钟
      points: 0,
      totalCheckIns: 0,
      lastMilestoneAwarded: 0,
      termsAccepted: true,
      termsAcceptedAt: Date(),
      termsVersion: "1.0"
    )
    
    try await user.save(on: req.db)
    
    // 为新用户创建默认收藏夹和播放列表
    try await createDefaultFolder(for: user.id!, on: req)
    try await createDefaultPlaylist(for: user.id!, on: req)
    
    return BasicResponse(success: true, message: "注册成功，您的用户名为：\(randomName)", id: user.id)
  }
  
  // 生成中文随机用户名：[积极的形容词]的[动物名词]
  private func generateChineseRandomName() -> String {
    let positiveAdjectives = [
      "勇敢", "聪明", "快乐", "善良", "可爱", 
      "机智", "温柔", "活泼", "开朗", "诚实",
      "乐观", "坚强", "文雅", "睿智", "敏捷"
    ]
    
    let animals = [
      "熊猫", "老虎", "狮子", "大象", "猴子",
      "兔子", "狐狸", "猫咪", "小狗", "鹿",
      "鸽子", "蝴蝶", "小鸟", "海豚", "企鹅"
    ]
    
    let randomAdjective = positiveAdjectives.randomElement() ?? "快乐"
    let randomAnimal = animals.randomElement() ?? "熊猫"
    
    return "\(randomAdjective)的\(randomAnimal)"
  }
  
    // MARK: - 登录方法
  @Sendable
  func login(req: Request) async throws -> Response {
    let login: User.Login = try req.content.decode(User.Login.self)
    
    // 检查用户协议是否同意
    if !login.agreedToTerms {
      throw Abort(.badRequest, reason: "请先同意用户协议")
    }
    
    let user: User? = try await User.query(on: req.db)
      .group(.or) { or in
        or.filter(\.$name == login.identifier)
        or.filter(\.$email == login.identifier)
        or.filter(\.$phone == login.identifier)
      }
      .first()
    
    guard let user: User = user else {
      throw Abort(.badRequest, reason: "用户不存在，请确认账号是否正确")
    }
    
    if login.agreedToTerms && (user.termsVersion != "1.0" || !user.termsAccepted ) {
      user.termsAccepted = true
      user.termsAcceptedAt = Date()
      user.termsVersion = "1.0"
      try await user.save(on: req.db)
    }

    guard try Bcrypt.verify(login.password, created: user.password) else {
      throw Abort(.badRequest, reason: "密码错误，请重新输入")
    }
    
      // 检查并为用户创建默认收藏夹（如果还没有）
    try await createDefaultFolder(for: user.id!, on: req)
    
      // 检查并为用户创建默认播放列表（如果还没有）
    try await createDefaultPlaylist(for: user.id!, on: req)
    
    let sessionID = UUID().uuidString
    let sessionKey = RedisKey("session:\(sessionID)")
    try await req.redis.set(sessionKey, to: user.id!.uuidString).get()
    let _ = req.redis.expire(sessionKey, after: sessionExpiration)
    
    req.headers.replaceOrAdd(name: .authorization, value: sessionID)
    
    let response = Response(status: .ok)
    response.headers.add(name: .authorization, value: sessionID)
    let basicResponse = BasicResponse(success: true, message: "登录成功")
    try response.content.encode(basicResponse)
    return response
  }
  
    // 使用邮箱验证码登录
  @Sendable
  func loginWithEmailCode(req: Request) async throws -> Response {
    let loginData: User.EmailCodeLogin = try req.content.decode(User.EmailCodeLogin.self)
    
      // 检查用户协议是否同意
    if !loginData.agreedToTerms {
      throw Abort(.badRequest, reason: "请先同意用户协议")
    }

      // 验证邮箱验证码
    let verificationResult: VerificationCodeService.VerificationResult = try await req.verificationCodeService.verifyCodeAsync(
      for: loginData.email,
      type: .emailLogin,
      code: loginData.code,
      on: req
    )
    
    guard verificationResult.isSuccess else {
      throw Abort(.badRequest, reason: verificationResult.errorMessage)
    }
    
      // 查找用户
    guard let user: User = try await User.query(on: req.db)
      .filter(\.$email == loginData.email)
      .first() else {
      throw Abort(.notFound, reason: "该邮箱未注册，请先注册")
    }
    
    if loginData.agreedToTerms && (user.termsVersion != "1.0" || !user.termsAccepted ) {
      user.termsAccepted = true
      user.termsAcceptedAt = Date()
      user.termsVersion = "1.0"
      try await user.save(on: req.db)
    }

      // 检查并为用户创建默认收藏夹和播放列表（如果还没有）
    try await createDefaultFolder(for: user.id!, on: req)
    try await createDefaultPlaylist(for: user.id!, on: req)
    
      // 生成会话并返回token
    let sessionID: String = UUID().uuidString
    let sessionKey: RedisKey = RedisKey("session:\(sessionID)")
    try await req.redis.set(sessionKey, to: user.id!.uuidString).get()
    if try await req.redis.expire(sessionKey, after: sessionExpiration).get() {
      req.logger.debug("Session expiration set successfully")
    } else {
      req.logger.warning("Failed to set session expiration")
    }
    
    
    let response: Response = Response(status: .ok)
    response.headers.add(name: .authorization, value: sessionID)
    let basicResponse: BasicResponse = BasicResponse(success: true, message: "登录成功")
    try response.content.encode(basicResponse)
    return response
  }
  
    // 使用手机验证码登录
  @Sendable
  func loginWithPhoneCode(req: Request) async throws -> Response {
    let loginData: User.PhoneCodeLogin = try req.content.decode(User.PhoneCodeLogin.self)
    
      // 检查用户协议是否同意
    if !loginData.agreedToTerms {
      throw Abort(.badRequest, reason: "请先同意用户协议")
    }

      // 验证手机验证码
    let verificationResult: VerificationCodeService.VerificationResult = try await req.verificationCodeService.verifyCodeAsync(
      for: loginData.phone,
      type: .phoneLogin,
      code: loginData.code,
      on: req
    )
    
    guard verificationResult.isSuccess else {
      throw Abort(.badRequest, reason: verificationResult.errorMessage)
    }
    
      // 查找用户
    guard let user = try await User.query(on: req.db)
      .filter(\.$phone == loginData.phone)
      .first() else {
      throw Abort(.notFound, reason: "该手机号未注册，请先注册")
    }

    if loginData.agreedToTerms && (user.termsVersion != "1.0" || !user.termsAccepted ) {
      user.termsAccepted = true
      user.termsAcceptedAt = Date()
      user.termsVersion = "1.0"
      try await user.save(on: req.db)
    }
    
      // 检查并为用户创建默认收藏夹和播放列表（如果还没有）
    try await createDefaultFolder(for: user.id!, on: req)
    try await createDefaultPlaylist(for: user.id!, on: req)
    
      // 生成会话并返回token
    let sessionID = UUID().uuidString
    let sessionKey = RedisKey("session:\(sessionID)")
    try await req.redis.set(sessionKey, to: user.id!.uuidString).get()
 
    guard try await req.redis
      .expire(sessionKey, after: sessionExpiration)
      .get() else {
      throw Abort(.internalServerError)
    }
      
      let response = Response(status: .ok)
        response.headers.add(name: .authorization, value: sessionID)
        let basicResponse = BasicResponse(success: true, message: "登录成功")
        try response.content.encode(basicResponse)
        return response
  }
  
    // 发送邮箱验证码
  @Sendable
  func sendEmailVerificationCode(req: Request) async throws -> BasicResponse {
      // 解析请求参数
    struct EmailRequest: Content {
      let email: String
      let type: String // login, change, reset
    }
    
    let emailReq = try req.content.decode(EmailRequest.self)
    
      // 确定验证码类型
    let verificationType: VerificationCodeService.VerificationType
    switch emailReq.type {
      case "login":
        verificationType = .emailLogin
      case "change":
        verificationType = .emailChange
      case "reset":
        verificationType = .emailResetPassword
      default:
        throw Abort(.badRequest, reason: "不支持的验证类型")
    }
    
      // 发送验证码
    let _ = try await req.verificationCodeService.sendEmailCode(email: emailReq.email, type: verificationType, req: req)
    
    return BasicResponse(success: true, message: "验证码已发送，请在10分钟内完成验证")
  }
  
    // 发送短信验证码
  @Sendable
  func sendSMSVerificationCode(req: Request) async throws -> BasicResponse {
      // 解析请求参数
    struct SMSRequest: Content {
      let phone: String
      let type: String // login, change, reset
    }
    
    let smsReq = try req.content.decode(SMSRequest.self)
    
      // 确定验证码类型
    let verificationType: VerificationCodeService.VerificationType
    switch smsReq.type {
      case "login":
        verificationType = .phoneLogin
      case "change":
        verificationType = .phoneChange
      case "reset":
        verificationType = .phoneResetPassword
      default:
        throw Abort(.badRequest, reason: "不支持的验证类型")
    }
    
      // 发送验证码
    let _ = try await req.verificationCodeService.sendSMSCode(to: smsReq.phone, type: verificationType, on: req)
    
    return BasicResponse(success: true, message: "验证码已发送，请在10分钟内完成验证")
  }
  
    // 创建默认收藏夹
  private func createDefaultFolder(for userID: UUID, on req: Request) async throws {
      // 检查是否已存在默认收藏夹
    let existingFolder = try await Folder.query(on: req.db)
      .filter(\.$user.$id == userID)
      .filter(\.$isDefault == true)
      .first()
    
    if existingFolder == nil {
        // 创建默认收藏夹
      let defaultFolder = Folder(
        name: "默认收藏夹",
        isDefault: true,
        userID: userID
      )
      
      try await defaultFolder.save(on: req.db)
      req.logger.info("已为新用户 \(userID) 创建默认收藏夹")
      
        // 清除用户收藏夹相关缓存
      let favoriteCache = FavoriteCache(req: req)
      try await favoriteCache.clearUserFavoriteCache(userID: userID, on: req)
    }
  }
  
    // 创建默认播放列表
  private func createDefaultPlaylist(for userID: UUID, on req: Request) async throws {
      // 检查是否已存在默认播放列表（收藏类型）
    let existingPlaylist = try await Playlist.query(on: req.db)
      .filter(\.$user.$id == userID)
      .filter(\.$type == .favorite)
      .filter(\.$isDeleted == false)
      .first()
    
    if existingPlaylist == nil {
        // 创建默认播放列表
      let defaultPlaylist = Playlist(
        name: "我喜欢的听力",
        description: "收藏的听力内容",
        userID: userID,
        audioIds: [],
        audioAddedDates: [:],
        type: .favorite,
        sortOrder: 0,
        isDeleted: false
      )
      
      try await defaultPlaylist.save(on: req.db)
      req.logger.info("已为新用户 \(userID) 创建默认播放列表「我喜欢的听力」")
      
        // 清除用户播放列表缓存，确保新创建的播放列表能立即被获取到
      let cacheKey = CacheConfig.KeyBuilder.playlistsForUser(userID: userID)
      try await req.cache.delete(forKey: cacheKey, on: req.redis)
    }
  }
  
  @Sendable
  func fetchMe(req: Request) async throws -> User {
    let uuid = try req.authenticatedUserID
    let cacheKey = RedisKey("user:\(uuid)")
    if let cacheUser = try await req.redis.get(cacheKey, asJSON: User.self) {
      // 兜底：如果缓存中的 avatar 不是完整 URL，尝试修正
      if let avatar = cacheUser.avatar, !avatar.isEmpty, !avatar.hasPrefix("http") {
        do {
          cacheUser.avatar = try await req.cosServiceProxy.generateAvatarUrl(for: avatar)
        } catch {
          req.logger.error("生成头像URL失败: \(error.localizedDescription), userId: \(uuid), avatar: \(avatar)")
          // 兜底拼接
          cacheUser.avatar = "https://bayanarabic-user-uploads-1329464674.cos.ap-beijing.myqcloud.com/\(avatar)"
        }
      }
      
      // 确保 dailyGoal 有有效值
      if cacheUser.dailyGoal <= 0 {
        cacheUser.dailyGoal = 600 // 默认10分钟
        // 缓存中发现无效值，需要更新数据库
        if let user = try await User.find(uuid, on: req.db) {
          user.dailyGoal = 600
          try await user.save(on: req.db)
          // 更新缓存
          try await req.redis.set(cacheKey, toJSON: user)
          let _ = req.redis.expire(cacheKey, after: .hours(1))
        }
      }
      
      return cacheUser
    }
    guard let user: User = try await User.find(uuid, on: req.db) else {
      throw Abort(.notFound, reason: "用户不存在，请重新登录")
    }
    
    // 确保 dailyGoal 有有效值
    if user.dailyGoal <= 0 {
      user.dailyGoal = 600 // 默认10分钟
      try await user.save(on: req.db)
    }
    
    // 头像处理逻辑
    if let avatar: String = user.avatar, !avatar.isEmpty {
      do {
        if !avatar.hasPrefix("http") {
          user.avatar = try await req.cosServiceProxy.generateAvatarUrl(for: avatar)
        }
      } catch {
        req.logger.error("生成头像URL失败: \(error.localizedDescription), userId: \(uuid), avatar: \(avatar)")
        user.avatar = "https://bayanarabic-user-uploads-1329464674.cos.ap-beijing.myqcloud.com/\(avatar)"
      }
      // 多尺寸头像
      if req.headers.first(name: "X-Avatar-Details") == "1" {
        do {
          let avatarDetails = try await req.cosServiceProxy.processAvatar(for: avatar)
          user.avatarUrls = avatarDetails.avatarUrls
        } catch {
          req.logger.error("获取多尺寸头像失败: \(error.localizedDescription), userId: \(uuid), avatar: \(avatar)")
        }
      }
    }
    try await req.redis.set(cacheKey, toJSON: user)
    let _ = req.redis.expire(cacheKey, after: .hours(1))
    return user
  }
  
  @Sendable
  func updateMe(req: Request) async throws -> BasicResponse {
    let uuid = try req.authenticatedUserID
    
    return try await req.db.transaction { database in
      guard let user = try await User.find(uuid, on: database) else {
        throw Abort(.notFound, reason: "用户不存在，请重新登录")
      }
      
      let update = try req.content.decode(User.Update.self)
      
      try await updateUserInfo(user: user, with: update, on: database)
      
      try await updateUserCache(for: user, on: req)
      
      return BasicResponse(success: true, message: "用户信息更新成功")
    }
  }
  
  @Sendable
  func logout(req: Request) async throws -> BasicResponse {
    
    let uuid = try req.authenticatedUserID
    
    guard let sessionID = req.headers.bearerAuthorization?.token else {
      throw Abort(.badRequest, reason: "未登录，无需登出")
    }
    
    let sessionKey = RedisKey("session:\(sessionID)")
    let userCacheKey = RedisKey("user:\(uuid)")
    let userRelatedCacheKey = RedisKey("user-\(uuid)-*")
    
      // 并行清除所有相关缓存
    async let deleteSession = req.redis.delete(sessionKey)
    async let deleteUserCache = req.redis.delete(userCacheKey)
    async let deleteRelatedCache = req.redis.delete(userRelatedCacheKey)
    
    let _ = await [deleteSession, deleteUserCache, deleteRelatedCache].isEmpty
    
    req.session.data["userID"] = nil
    req.session.destroy()
    
    return BasicResponse(success: true, message: "登出成功，欢迎再次登录")
  }
  
    // 绑定/更新手机号
  @Sendable
  func bindPhone(req: Request) async throws -> BasicResponse {
    let uuid = try req.authenticatedUserID
    let bindRequest = try req.content.decode(User.BindRequest.self)
    
    guard bindRequest.type == "phone" else {
      throw Abort(.badRequest, reason: "请求类型错误")
    }
    
      // 验证手机验证码
    let verificationResult = try await req.verificationCodeService.verifyCodeAsync(
      for: bindRequest.identifier,
      type: .phoneChange,
      code: bindRequest.code,
      on: req
    )
    
    guard verificationResult.isSuccess else {
      throw Abort(.badRequest, reason: verificationResult.errorMessage)
    }
    
      // 检查手机号是否已被其他账户使用
    if try await User.query(on: req.db)
      .filter(\.$phone == bindRequest.identifier)
      .filter(\.$id != uuid)
      .first() != nil {
      throw Abort(.conflict, reason: "该手机号已被其他账户绑定")
    }
    
    guard let user = try await User.find(uuid, on: req.db) else {
      throw Abort(.notFound, reason: "用户不存在，请重新登录")
    }
    
      // 更新手机号和验证状态
    user.phone = bindRequest.identifier
    user.isPhoneVerified = true
    
    try await user.save(on: req.db)
    try await updateUserCache(for: user, on: req)
    
    return BasicResponse(success: true, message: "手机号绑定成功")
  }
  
    // 绑定/更新邮箱
  @Sendable
  func bindEmail(req: Request) async throws -> BasicResponse {
    let uuid = try req.authenticatedUserID
    let bindRequest = try req.content.decode(User.BindRequest.self)
    
    guard bindRequest.type == "email" else {
      throw Abort(.badRequest, reason: "请求类型错误")
    }
    
      // 验证邮箱验证码
    let verificationResult = try await req.verificationCodeService.verifyCodeAsync(
      for: bindRequest.identifier,
      type: .emailChange,
      code: bindRequest.code,
      on: req
    )
    
    guard verificationResult.isSuccess else {
      throw Abort(.badRequest, reason: verificationResult.errorMessage)
    }
    
      // 检查邮箱是否已被其他账户使用
    if try await User.query(on: req.db)
      .filter(\.$email == bindRequest.identifier)
      .filter(\.$id != uuid)
      .first() != nil {
      throw Abort(.conflict, reason: "该邮箱已被其他账户绑定")
    }
    
    guard let user = try await User.find(uuid, on: req.db) else {
      throw Abort(.notFound, reason: "用户不存在，请重新登录")
    }
    
      // 更新邮箱和验证状态
    let _ = user.email
    user.email = bindRequest.identifier
    user.isEmailVerified = true
    
    try await user.save(on: req.db)
    try await updateUserCache(for: user, on: req)
    
    return BasicResponse(success: true, message: "邮箱绑定成功")
  }
  
  private func updateUserInfo(user: User, with update: User.Update, on database: Database) async throws {
    user.name = update.name ?? user.name
    user.email = update.email ?? user.email
    user.phone = update.phone ?? user.phone
    user.bio = update.bio ?? user.bio
    
      // 只有当提供了新密码时才更新密码
    if let newPassword = update.password, newPassword != user.password {
      user.password = try Bcrypt.hash(newPassword)
    }
    
    user.avatar = update.avatar ?? user.avatar
    user.isEmailVerified = update.isEmailVerified ?? user.isEmailVerified
    user.isPhoneVerified = update.isPhoneVerified ?? user.isPhoneVerified
    user.isSubscribed = update.isSubscribed ?? user.isSubscribed
    
    try await user.save(on: database)
  }
  
  private func updateUserCache(for user: User, on req: Request) async throws {
    let cacheKey = RedisKey("user:\(user.id!)")
    let userRelatedCacheKey = RedisKey("user:\(user.id!):related")
    
    async let deleteUserCache = req.redis.delete(cacheKey)
    async let deleteRelatedCache = req.redis.delete(userRelatedCacheKey)
    
      // 等待缓存删除完成
    _ = await [deleteUserCache, deleteRelatedCache]
    
      // 设置新的缓存
    try await req.redis.set(cacheKey, toJSON: user)
    let _ = req.redis.expire(cacheKey, after: .hours(24))
  }
  
  // MARK: - 密码重置相关方法
  // 忘记密码 - 发送验证码
  @Sendable
  func forgetPassword(req: Request) async throws -> BasicResponse {
    // 解析请求参数
    struct ForgetPasswordRequest: Content {
      let identifier: String // 可以是邮箱或手机号
      let type: String // "email" 或 "phone"
    }
    
    let forgetRequest = try req.content.decode(ForgetPasswordRequest.self)
    let identifier = forgetRequest.identifier
    let isEmail = forgetRequest.type == "email"
    
    // 检查用户是否存在
    let userQuery = User.query(on: req.db)
    if isEmail {
      userQuery.filter(\.$email == identifier)
    } else {
      userQuery.filter(\.$phone == identifier)
    }
    
    guard try await userQuery.first() != nil else {
      throw Abort(.notFound, reason: isEmail ? "该邮箱未注册，请先注册账号" : "该手机号未注册，请先注册账号")
    }
    
    // 生成验证码并存储
    let code = req.verificationCodeService.generateCode()
    let verificationType = isEmail ? VerificationCodeService.VerificationType.emailResetPassword : 
                                    VerificationCodeService.VerificationType.phoneResetPassword
    
    try await req.verificationCodeService.storeCode(
      for: identifier,
      type: verificationType,
      code: code,
      on: req
    )
    
    if isEmail {
      // 发送重置密码邮件
      try await req.application.tencentEmail.sendResetPasswordEmail(to: identifier, code: code)
      return BasicResponse(success: true, message: "重置密码验证码已发送至您的邮箱，请在10分钟内完成验证")
    } else {
      // 发送重置密码短信 - 使用腾讯云短信服务
      // 检查是否是国际号码
      let isInternational = !identifier.hasPrefix("+86") && identifier.hasPrefix("+")
      try await req.application.tencentSMS.sendSMS(to: identifier, code: code, international: isInternational)
      return BasicResponse(success: true, message: "重置密码验证码已发送至您的手机，请在10分钟内完成验证")
    }
  }
  
  // 重置密码
  @Sendable
  func resetPassword(req: Request) async throws -> BasicResponse {
    // 解析请求参数
    struct ResetPasswordRequest: Content {
      let identifier: String // 邮箱或手机号
      let type: String // "email" 或 "phone"
      let code: String
      let newPassword: String
    }
    
    let resetRequest = try req.content.decode(ResetPasswordRequest.self)
    let identifier = resetRequest.identifier
    let isEmail = resetRequest.type == "email"
    
    // 验证验证码
    let verificationType = isEmail ? VerificationCodeService.VerificationType.emailResetPassword : 
                                    VerificationCodeService.VerificationType.phoneResetPassword
    
    let verificationResult = try await req.verificationCodeService.verifyCodeAsync(
      for: identifier,
      type: verificationType,
      code: resetRequest.code,
      on: req
    )
    
    guard verificationResult.isSuccess else {
      throw Abort(.badRequest, reason: verificationResult.errorMessage)
    }
    
    // 查找用户并更新密码
    let userQuery = User.query(on: req.db)
    if isEmail {
      userQuery.filter(\.$email == identifier)
    } else {
      userQuery.filter(\.$phone == identifier)
    }
    
    guard let user = try await userQuery.first() else {
      throw Abort(.notFound, reason: "用户不存在")
    }
    
    // 更新密码
    user.password = try Bcrypt.hash(resetRequest.newPassword)
    try await user.save(on: req.db)
    
    // 清除用户相关缓存
    try await updateUserCache(for: user, on: req)
    
    return BasicResponse(success: true, message: "密码重置成功，请使用新密码登录")
  }

  @Sendable
  func getTermsInfo(req: Request) async throws -> User.TermsInfo {
    var requireNewAgreement: Bool = false

    // Try to get authenticated user ID, but don't throw if not authenticated
    if let bearer = req.headers.bearerAuthorization?.token,
       let userIDString = try? await req.redis.get(RedisKey("session:\(bearer)")).get().string,
       let userID = UUID(uuidString: userIDString),
       let user = try await User.find(userID, on: req.db) {
      // 如果用户的版本与当前版本不同或者用户未同意条款
      requireNewAgreement = user.termsVersion != "1.0" || !user.termsAccepted
    }

    let termsInfo: User.TermsInfo = User.TermsInfo(
      currentTermsVersion: "1.0",
      currentPrivacyVersion: "1.0",
      termsUrl: "https://www.bayanarabic.cn/terms/embedded",
      privacyUrl: "https://www.bayanarabic.cn/privacy/embedded",
      requireNewAgreement: requireNewAgreement
    )
    
    return termsInfo
  }

  @Sendable
  func updateTermsAgreement(req: Request) async throws -> BasicResponse {
    let uuid = try req.authenticatedUserID
    let termsAgreement: User.TermsAgreement = try req.content.decode(User.TermsAgreement.self)
    
    guard let user = try await User.find(uuid, on: req.db) else {
      throw Abort(.notFound, reason: "用户不存在")
    }
    
    user.termsAccepted = termsAgreement.agreedToTerms
    user.termsAcceptedAt = Date()
    user.termsVersion = termsAgreement.termsVersion
    
    try await user.save(on: req.db)
    try await updateUserCache(for: user, on: req)
    
    return BasicResponse(success: true, message: "用户协议更新成功")
  }

  // MARK: - Apple登录方法
  @Sendable
  func appleSignIn(req: Request) async throws -> Response {
    // 解析Apple登录请求
    let signInRequest = try req.content.decode(User.AppleSignInRequest.self)
    
    // 记录原始请求信息，帮助调试
    req.logger.debug("开始Apple登录认证，令牌长度: \(signInRequest.identityToken.count)字符")
    
    // 验证Apple身份令牌
    let appleVerifier = try AppleSignInVerifier(
      teamID: "926XCQXMCH",
      clientID: "cn.bayanarabic.bayan.tingli",
      keyID: "J63J9GJJ98",
      privateKeyPath: "/root/Certs/AuthKey_J63J9GJJ98.p8"
    )
    
    do {
      let verificationResult = try await appleVerifier.verify(identityToken: signInRequest.identityToken)
      
      guard verificationResult.isValid else {
        req.logger.warning("Apple身份验证失败: \(verificationResult.errorMessage ?? "未知错误")")
        throw Abort(.unauthorized, reason: "Apple身份验证失败: \(verificationResult.errorMessage ?? "未知错误")")
      }
      
      // 从验证结果中提取用户信息
      guard let appleUserID = verificationResult.userID else {
        req.logger.error("无法从Apple令牌中提取用户ID")
        throw Abort(.internalServerError, reason: "无法从Apple令牌中提取用户ID")
      }
      
      req.logger.info("Apple验证成功，用户ID: \(appleUserID), 邮箱: \(verificationResult.email ?? "未提供")")
      
      // 检查用户是否已存在（通过Apple ID）
      var user = try await User.query(on: req.db)
        .filter(\.$appleUserID == appleUserID)
        .filter(\.$isDeleted == false)
        .first()
      
      if user == nil {
        // 用户不存在，创建新用户
        let email = verificationResult.email ?? "\(UUID().uuidString)@privaterelay.appleid.com"
        let name = signInRequest.fullName ?? generateChineseRandomName()
        
        // 检查邮箱是否已被其他账户使用
        if let existingUser = try await User.query(on: req.db)
          .filter(\.$email == email)
          .filter(\.$isDeleted == false)
          .first() {
          // 如果邮箱已被使用，但不是Apple登录，更新该用户的Apple ID
          existingUser.appleUserID = appleUserID
          try await existingUser.save(on: req.db)
          user = existingUser
        } else {
          // 创建全新用户
          let newUser = User(
            name: name,
            email: email,
            password: try Bcrypt.hash(UUID().uuidString), // 生成随机密码
            isDeleted: false,
            isEmailVerified: true, // Apple已验证邮箱
            isPhoneVerified: false,
            isSubscribed: false,
            currentStreak: 0,
            dailyGoal: 600, // 默认10分钟
            points: 0,
            totalCheckIns: 0,
            lastMilestoneAwarded: 0,
            termsAccepted: signInRequest.agreedToTerms,
            termsAcceptedAt: Date(),
            termsVersion: "1.0",
            appleUserID: appleUserID
          )
          
          try await newUser.save(on: req.db)
          user = newUser
          
          // 为新用户创建默认收藏夹和播放列表
          try await createDefaultFolder(for: newUser.id!, on: req)
          try await createDefaultPlaylist(for: newUser.id!, on: req)
        }
      } else if signInRequest.agreedToTerms && (user!.termsVersion != "1.0" || !user!.termsAccepted) {
        // 更新用户协议同意状态
        user!.termsAccepted = true
        user!.termsAcceptedAt = Date()
        user!.termsVersion = "1.0"
        try await user!.save(on: req.db)
      }
      
      guard let finalUser = user else {
        throw Abort(.internalServerError, reason: "用户创建失败")
      }
      
      // 创建用户会话
      let sessionID = UUID().uuidString
      let sessionKey = RedisKey("session:\(sessionID)")
      try await req.redis.set(sessionKey, to: finalUser.id!.uuidString).get()
      let _ = req.redis.expire(sessionKey, after: sessionExpiration)
      
      // 检查并确保用户有默认收藏夹和播放列表
      try await createDefaultFolder(for: finalUser.id!, on: req)
      try await createDefaultPlaylist(for: finalUser.id!, on: req)
      
      // 返回登录响应
      let response = Response(status: .ok)
      response.headers.add(name: .authorization, value: sessionID)
      let basicResponse = BasicResponse(success: true, message: "Apple登录成功")
      try response.content.encode(basicResponse)
      return response
    } catch {
      req.logger.error("Apple身份验证失败: \(error.localizedDescription)")
      throw Abort(.internalServerError, reason: "Apple身份验证失败")
    }
  }
}


struct BasicResponse: Content, Codable {
  var success: Bool
  var message: String
  var id: UUID?
  var data: [String: String]?
  
  init(success: Bool, message: String, id: UUID? = nil, data: [String: String]? = nil) {
    self.success = success
    self.message = message
    self.id = id
    self.data = data
  }
}
